package com.tjvib.view.activity;

import static com.tjvib.Constants.SENSOR_TYPE_LPMSB2;

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.NumberPicker;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.jjoe64.graphview.series.DataPoint;
import com.tjvib.R;
import com.tjvib.adapter.SensorSelectAdapter;
import com.tjvib.bean.SensorSelect;
import com.tjvib.presenter.LpmsB2SensorPresenter;
import com.tjvib.sensor.LpmsB2Sensor;
import com.tjvib.sensor.LpmsB2SensorData;
import com.tjvib.util.LogUtil;
import com.tjvib.util.ToastUtil;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class LpmsB2SensorActivity extends SensorActivity<LpmsB2SensorPresenter, LpmsB2SensorData> {

    public static long firstTimestamp = 0;
    private List<SensorSelect> sensorSelectList = new ArrayList<>();
    private SensorSelectAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    protected void onResume() {
        super.onResume();
        presenter.startOrBindToService();
    }

    @Override
    protected void onStop() {
        presenter.stopReadingData();
        presenter.unbindFromService();
        super.onStop();
    }

    @Override
    String getSensorName() {
        return "LPMS-B2 Sensor";
    }

    @Override
    protected int initLayout() {
        return R.layout.activity_lpmsb2_sensor;
    }

    @Override
    protected boolean initView() {
        ImageView sen_iv_choose = findViewById(R.id.sen_iv_choose);
        sen_iv_choose.setOnClickListener(v -> showSensorDialog());

        sen_tv_tit = findViewById(R.id.sen_tv_tit);
        sen_tv_tit.setText("LPMS-B2传感器");
        sen_tv_tit.setOnClickListener(v -> showSensorDialog());

        sen_iv_set = findViewById(R.id.sen_iv_set);
        sen_iv_set.setOnClickListener(v -> showSettingDialog(SENSOR_TYPE_LPMSB2, (dialogInterface, i) -> {
            switch (i) {
                case 0:
                    presenter.resetTimestamp();
                    break;
                case 1:
                    settingsSetStreamFreq();
                    break;
                case 2:
                    settingsSetImuId();
                    break;
                case 3:
                    settingsSetGyroRange();
                    break;
                case 4:
                    settingsSetAccRange();
                    break;
                case 5:
                    settingsSetMagRange();
                    break;
                case 6:
                    settingsSetTransmitData();
                    break;
                case 7:
                    settingsSetFilterMode();
                    break;
                case 8:
                    settingsSetOrientationOffset();
                    break;
            }
        }));
        return true;
    }

    @Override
    protected boolean initData() {
        adapter = new SensorSelectAdapter(R.layout.item_sensor_select, this, sensorSelectList);
        firstTimestamp = System.currentTimeMillis();
        return true;
    }

    @Override
    void setInfoLayoutData(LpmsB2SensorData data) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
        sen_tv_data = findViewById(R.id.sen_tv_data);
        sen_tv_info1 = findViewById(R.id.sen_tv_info1);
        sen_tv_info2 = findViewById(R.id.sen_tv_info2);

        sen_tv_data.setText(getString(R.string.ui_lpmsb2_sensor_data,
                format.format(new Date(data.localtime)),
                data.timestamp,
                data.batteryLevel, data.chargingStatus,
                data.temperature, data.pressure, data.altitude,
                data.quat[0], data.quat[1], data.quat[2], data.quat[3],
                data.angVel[0], data.angVel[1], data.angVel[2],
                data.euler[0], data.euler[1], data.euler[2],
                data.acc[0], data.acc[1], data.acc[2],
                data.mag[0], data.mag[1], data.mag[2],
                data.gyr[0], data.gyr[1], data.gyr[2],
                data.linAcc[0], data.linAcc[1], data.linAcc[2]
        ));
        sen_tv_info1.setText(getString(R.string.ui_lpmsb2_sensor_info1,
                presenter.getImuId(),
                presenter.getGyroRange(),
                presenter.getMagRange()));
        sen_tv_info2.setText(getString(R.string.ui_lpmsb2_sensor_info2,
                presenter.getStreamFreq(),
                presenter.getAccRange(),
                "" + presenter.getFilterMode()));
    }

    @Override
    void setImageLayoutData(LpmsB2SensorData data) {
        if (isDrawing && data.localtime > switchTime) {
            graph2LastXValue = graph2LastXValue + 1.0D;
            float[] dataToShow = new float[3];
            int i = 0;
            if (this.dataSelect == R.id.sen_rb_acc) {
                while (i < 3) {
                    dataToShow[i] = data.acc[i];
                    i += 1;
                }
            } else if (this.dataSelect == R.id.sen_rb_mag) {
                i = 0;
                while (i < 3) {
                    dataToShow[i] = data.mag[i];
                    i += 1;
                }
            } else if (this.dataSelect == R.id.sen_rb_gyr) {
                i = 0;
                while (i < 3) {
                    dataToShow[i] = data.gyr[i];
                    i += 1;
                }
            } else if (this.dataSelect == R.id.sen_rb_lin) {
                i = 0;
                while (i < 3) {
                    dataToShow[i] = data.linAcc[i];
                    i += 1;
                }
            }

            mSeries1.appendData(new DataPoint((data.localtime - firstTimestamp)/1000f, dataToShow[0]), true, 50);
            mSeries2.appendData(new DataPoint((data.localtime - firstTimestamp)/1000f, dataToShow[1]), true, 50);
            mSeries3.appendData(new DataPoint((data.localtime - firstTimestamp)/1000f, dataToShow[2]), true, 50);
        }
    }

    @Override
    protected LpmsB2SensorPresenter genPresenter() {
        return new LpmsB2SensorPresenter(this);
    }

    @Override
    public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
        if (compoundButton.getId() == R.id.sen_rb_acc || compoundButton.getId() == R.id.sen_rb_mag
                || compoundButton.getId() == R.id.sen_rb_gyr || compoundButton.getId() == R.id.sen_rb_lin) {
            if (b) {
                dataSelect = compoundButton.getId();
                removeGraph();
                drawGraph();
            }
        } else if (compoundButton.getId() == R.id.sen_cb_x) {
            if (b) sen_gv_data.addSeries(mSeries1);
            else sen_gv_data.removeSeries(mSeries1);
        } else if (compoundButton.getId() == R.id.sen_cb_y) {
            if (b) sen_gv_data.addSeries(mSeries2);
            else sen_gv_data.removeSeries(mSeries2);
        } else if (compoundButton.getId() == R.id.sen_cb_z) {
            if (b) sen_gv_data.addSeries(mSeries3);
            else sen_gv_data.removeSeries(mSeries3);
        }
    }

    private void showSensorDialog() {
        TmpDialog dialog = new TmpDialog(this);
        View view = LayoutInflater.from(this).inflate(R.layout.dialog_select, null);
        dialog.setContentView(view);
        dialog.setCanceledOnTouchOutside(true);
        RecyclerView dialog_select_rv = view.findViewById(R.id.dialog_select_rv);
        dialog_select_rv.setLayoutManager(new LinearLayoutManager(this));
        dialog_select_rv.setAdapter(adapter);
        adapter.setOnItemClickListener((adapter, view1, position) -> {
            presenter.switchSensorInfo(position);
            refreshSensorSelectList();
            ToastUtil.show("切换中");
            dialog.dismiss();
        });
        dialog.show();
    }

    private class TmpDialog extends Dialog {
        public TmpDialog(@NonNull Context context) {
            super(context);
        }

        @Override
        public void show() {
            super.show();
            isDrawing = false;
        }

        @Override
        public void dismiss() {
            super.dismiss();
            isDrawing = true;
        }
    }


    public void refreshSensorSelectList() {
        runOnUiThread(() -> {
            sen_tv_tit = findViewById(R.id.sen_tv_tit);
            sen_tv_tit.setText(presenter.getCurName());
            sensorSelectList.clear();
            sensorSelectList.addAll(presenter.getSensorSelectList());
            adapter.notifyDataSetChanged();
        });
    }


    private void settingsSetImuId() {
        if (!presenter.isBound()) {
            ToastUtil.show("Service not started");
            return;
        }

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Set Imu ID: ");
        builder.setCancelable(false);

        final NumberPicker picker = new NumberPicker(this);
        int maxValue = 20;
        if (maxValue < presenter.getImuId())
            maxValue = presenter.getImuId();
        picker.setMinValue(1);
        picker.setMaxValue(maxValue);
        picker.setValue(presenter.getImuId());

        builder.setPositiveButton("Set",
                (dialog, id) -> {
                    try {
                        int ts = picker.getValue();
                        LogUtil.d("ts: " + ts);
                        presenter.setImuId(ts);
                    } catch (NumberFormatException nfe) {
                        System.out.println("Could not parse " + nfe);
                    }
                });
        builder.setNegativeButton("Cancel", null);
        builder.setView(picker);
        Dialog dialog = builder.create();
        dialog.show();
    }

    private void settingsSetStreamFreq() {
        if (!presenter.isBound()) {
            ToastUtil.show("Service not started");
            return;
        }

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Select Streaming Frequency: ");
        builder.setCancelable(false);

        final int[] freqArray = new int[]{5, 10, 25, 50, 100, 200, 400};
        CharSequence items[] = new CharSequence[]{"5Hz", "10Hz", "25Hz", "50Hz", "100Hz", "200Hz", "400Hz"};
        int currentFreq = presenter.getStreamFreq();
        int currentChoice;
        for (currentChoice = 0; currentChoice < freqArray.length; ++currentChoice) {
            if (currentFreq == freqArray[currentChoice]) {
                break;
            }
        }

        builder.setSingleChoiceItems(items, currentChoice, null);
        builder.setPositiveButton("Set",
                (dialog, id) -> {
                    ListView lw = ((AlertDialog) dialog).getListView();
                    int freq = freqArray[lw.getCheckedItemPosition()];
                    presenter.setStreamFreq(freq);
                });
        builder.setNegativeButton("Cancel", null);
        Dialog dialog = builder.create();
        dialog.show();
    }

    private void settingsSetGyroRange() {
        if (!presenter.isBound()) {
            ToastUtil.show("Service not started");
            return;
        }

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Select Gyro Range: ");
        builder.setCancelable(false);

        final int[] gyrArray = new int[]{125, 245, 500, 1000, 2000};
        CharSequence items[] = new CharSequence[]{"125dps", "245dps", "500dps", "1000dps", "2000dps"};
        int currentGyrRange = presenter.getGyroRange();
        int currentChoice;
        for (currentChoice = 0; currentChoice < gyrArray.length; ++currentChoice) {
            if (currentGyrRange == gyrArray[currentChoice]) {
                break;
            }
        }

        builder.setSingleChoiceItems(items, currentChoice, null);
        builder.setPositiveButton("Set",
                (dialog, id) -> {
                    ListView lw = ((AlertDialog) dialog).getListView();
                    int range = gyrArray[lw.getCheckedItemPosition()];
                    presenter.setGyroRange(range);
                });
        builder.setNegativeButton("Cancel", null);
        Dialog dialog = builder.create();
        dialog.show();
    }

    private void settingsSetAccRange() {
        if (!presenter.isBound()) {
            ToastUtil.show("Service not started");
            return;
        }

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Select Accelerometer Range: ");
        builder.setCancelable(false);

        final int[] accArray = new int[]{2, 4, 8, 16};
        CharSequence items[] = new CharSequence[]{"2G", "4G", "8G", "16G"};
        int currentAccRange = presenter.getAccRange();
        int currentChoice;
        for (currentChoice = 0; currentChoice < accArray.length; ++currentChoice) {
            if (currentAccRange == accArray[currentChoice]) {
                break;
            }
        }

        builder.setSingleChoiceItems(items, currentChoice, null);
        builder.setPositiveButton("Set",
                (dialog, id) -> {
                    ListView lw = ((AlertDialog) dialog).getListView();
                    int range = accArray[lw.getCheckedItemPosition()];
                    presenter.setAccRange(range);
                });
        builder.setNegativeButton("Cancel", null);
        Dialog dialog = builder.create();
        dialog.show();
    }

    private void settingsSetMagRange() {
        if (!presenter.isBound()) {
            ToastUtil.show("Service not started");
            return;
        }

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Select Magnetometer Range: ");
        builder.setCancelable(false);

        final int[] magArray = new int[]{4, 8, 12, 16};
        CharSequence items[] = new CharSequence[]{"2Gauss", "8Gauss", "12Gauss", "16Gauss"};
        int currentMagRange = presenter.getMagRange();
        int currentChoice;
        for (currentChoice = 0; currentChoice < magArray.length; ++currentChoice) {
            if (currentMagRange == magArray[currentChoice]) {
                break;
            }
        }

        builder.setSingleChoiceItems(items, currentChoice, null);
        builder.setPositiveButton("Set",
                (dialog, id) -> {
                    ListView lw = ((AlertDialog) dialog).getListView();
                    int range = magArray[lw.getCheckedItemPosition()];
                    presenter.setMagRange(range);
                });
        builder.setNegativeButton("Cancel", null);
        Dialog dialog = builder.create();
        dialog.show();
    }

    private void settingsSetTransmitData() {
        if (!presenter.isBound()) {
            ToastUtil.show("Service not started");
            return;
        }

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Select Transmission Data: ");
        builder.setCancelable(false);
        List<CharSequence> list = new ArrayList<CharSequence>();
        list.add("Accelerometer Data");
        list.add("Gyro Data");
        list.add("Magnetometer Data");
        list.add("Angular Velocity");
        list.add("Quaternion Data");
        list.add("Euler Angles");
        list.add("Linear Acceleration");
        list.add("Pressure Data");
        list.add("Altitude Data");
        list.add("Temperature Data");

        CharSequence items[] = list.toArray(new CharSequence[list.size()]);
        int count = items.length;
        boolean[] is_checked = new boolean[count]; // set is_checked boolean false;
        is_checked[0] = presenter.isAccDataEnabled();
        is_checked[1] = presenter.isGyroDataEnabled();
        is_checked[2] = presenter.isMagDataEnabled();
        is_checked[3] = presenter.isAngularVelDataEnable();
        is_checked[4] = presenter.isQuaternionDataEnabled();
        is_checked[5] = presenter.isEulerDataEnabled();
        is_checked[6] = presenter.isLinAccDataEnabled();
        is_checked[7] = presenter.isPressureDataEnabled();
        is_checked[8] = presenter.isAltitudeDataEnabled();
        is_checked[9] = presenter.isTemperatureDataEnabled();

        builder.setMultiChoiceItems(items, is_checked, null);
        builder.setPositiveButton("Set",
                (dialog, id) -> {
                    ListView list1 = ((AlertDialog) dialog).getListView();
                    int transmissionData = 0;
                    if (list1.isItemChecked(0))
                        transmissionData |= LpmsB2Sensor.LPMS_ACC_RAW_OUTPUT_ENABLED;
                    if (list1.isItemChecked(1))
                        transmissionData |= LpmsB2Sensor.LPMS_GYR_RAW_OUTPUT_ENABLED;
                    if (list1.isItemChecked(2))
                        transmissionData |= LpmsB2Sensor.LPMS_MAG_RAW_OUTPUT_ENABLED;
                    if (list1.isItemChecked(3))
                        transmissionData |= LpmsB2Sensor.LPMS_ANGULAR_VELOCITY_OUTPUT_ENABLED;
                    if (list1.isItemChecked(4))
                        transmissionData |= LpmsB2Sensor.LPMS_QUAT_OUTPUT_ENABLED;
                    if (list1.isItemChecked(5))
                        transmissionData |= LpmsB2Sensor.LPMS_EULER_OUTPUT_ENABLED;
                    if (list1.isItemChecked(6))
                        transmissionData |= LpmsB2Sensor.LPMS_LINACC_OUTPUT_ENABLED;
                    if (list1.isItemChecked(7))
                        transmissionData |= LpmsB2Sensor.LPMS_PRESSURE_OUTPUT_ENABLED;
                    if (list1.isItemChecked(8))
                        transmissionData |= LpmsB2Sensor.LPMS_ALTITUDE_OUTPUT_ENABLED;
                    if (list1.isItemChecked(9))
                        transmissionData |= LpmsB2Sensor.LPMS_TEMPERATURE_OUTPUT_ENABLED;

                    presenter.setTransmissionData(transmissionData);
                });
        builder.setNegativeButton("Cancel", null);
        Dialog dialog = builder.create();
        dialog.show();

    }

    private void settingsSetFilterMode() {
        if (!presenter.isBound()) {
            ToastUtil.show("Service not started");
            return;
        }

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Select Filter Mode: ");
        builder.setCancelable(false);

        CharSequence items[] = new CharSequence[]{"Gyr Only", "Gyr+Acc (Kalman)", "Gyr+Acc+Mag (Kalman)",
                "Gyr+Acc (DCM)", "Gyr+Acc+Mag (DCM)"};
        int currentFilterMode = presenter.getFilterMode();

        builder.setSingleChoiceItems(items, currentFilterMode, null);
        builder.setPositiveButton("Set",
                (dialog, id) -> {
                    ListView lw = ((AlertDialog) dialog).getListView();
                    presenter.setFilterMode(lw.getCheckedItemPosition());
                });
        builder.setNegativeButton("Cancel", null);
        Dialog dialog = builder.create();
        dialog.show();
    }

    private void settingsSetOrientationOffset() {
        if (!presenter.isBound()) {
            ToastUtil.show("Service not started");
            return;
        }

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Select Orientation Offset: ");
        builder.setCancelable(false);

        CharSequence items[] = new CharSequence[]{"Object Reset", "Heading Reset", "Alignment Reset", "Reset Offset"};

        builder.setSingleChoiceItems(items, 0, null);
        builder.setPositiveButton("Set",
                (dialog, id) -> {
                    ListView lw = ((AlertDialog) dialog).getListView();
                    switch (lw.getCheckedItemPosition()) {
                        case 0:
                            presenter.setOrientationOffset(LpmsB2Sensor.LPMS_OFFSET_MODE_OBJECT);
                            break;
                        case 1:
                            presenter.setOrientationOffset(LpmsB2Sensor.LPMS_OFFSET_MODE_HEADING);
                            break;
                        case 2:
                            presenter.setOrientationOffset(LpmsB2Sensor.LPMS_OFFSET_MODE_ALIGNMENT);
                            break;
                        case 3:
                            presenter.resetOrientationOffset();
                            break;
                    }
                });
        builder.setNegativeButton("Cancel", null);
        Dialog dialog = builder.create();
        dialog.show();
    }
}